# -*- coding: utf-8 -*-
# @Time    : 2018/5/29 下午10:59
# @Author  : Lavn
# @Email   : 959875529@qq.com
# @File    : magicMethon.py
# @Software: PyCharm

#在 Python 中，所有以 "__" 双下划线包起来的方法，都统称为"魔术方法"。比如我们接触最多的 __init__ 。魔术方法有什么作用呢？
#使用这些魔术方法，我们可以构造出优美的代码，将复杂的逻辑封装成简单的方法。
#我们可以使用 Python 内置的方法 dir() 来列出类中所有的魔术方法.示例如下：
# class User(object):
#     pass
# if __name__ == '__main__':
#     # 输出所有的方法
#     print(dir(User()))


# #先new对象  再init初始化对象
# class User(object):
#     def __new__(cls, *args, **kwargs):
#         # 打印 __new__方法中的相关信息
#         print('调用了 def __new__ 方法')
#         print(args)
#         # 最后返回父类的方法
#         return super(User, cls).__new__(cls)
#
#     def __init__(self, name, age):
#         print('调用了 def __init__ 方法')
#         self.name = name
#         self.age = age
#
#     # def __setattr__(self, name, value):
#     #     self.name = value
#     #     # 每当属性被赋值的时候， ``__setattr__()`` 会被调用，这样就造成了递归调用。
#     #     # 这意味这会调用 ``self.__setattr__('name', value)`` ，每次方法会调用自己。这样会造成程序崩溃。
#
#     def __setattr__(self, name, value):
#         # 给类中的属性名分配值
#         print((name,value))
#         self.__dict__[name] = value
#         # 定制特有属性
#
#
# if __name__ == '__main__':
#      usr = User('两点水', 23)



#方法	说明
#__getattr__(self, name)	该方法定义了你试图访问一个不存在的属性时的行为。
#因此，重载该方法可以实现捕获错误拼写然后进行重定向, 或者对一些废弃的属性进行警告。
#__setattr__(self, name, value)	定义了对属性进行赋值和修改操作时的行为。不管对象的某个属性是否存在,都允许为该属性进行赋值.有一点需要注意，
#实现 __setattr__ 时要避免"无限递归"的错误，
#__delattr__(self, name)	__delattr__ 与 __setattr__ 很像，只是它定义的是你删除属性时的行为。实现 __delattr__ 是同时要避免"无限递归"的错误
#__getattribute__(self, name)	__getattribute__ 定义了你的属性被访问时的行为，相比较，__getattr__ 只有该属性不存在时才会起作用。
#因此，在支持 __getattribute__的 Python 版本,调用__getattr__ 前必定会调用 __getattribute__``__getattribute__ 同样要避免"无限递归"的错误。

class User(object):
    def __getattr__(self, name):
        print('调用了 __getattr__ 方法')
        print(name)
        return super(User, self).__getattr__(name)

    def __setattr__(self, name, value):
        print('调用了 __setattr__ 方法')
        return super(User, self).__setattr__(name, value)

    def __delattr__(self, name):
        print('调用了 __delattr__ 方法')
        return super(User, self).__delattr__(name)

    def __getattribute__(self, name):
        print('调用了 __getattribute__ 方法')
        print(name)
        return super(User, self).__getattribute__(name)


if __name__ == '__main__':
    user = User()
    # 设置属性值，会调用 __setattr__
    user.attr1 = True
    # 属性存在,只有__getattribute__调用
    user.attr1
    try:
        # 属性不存在, 先调用__getattribute__, 后调用__getattr__
        user.attr2
    except AttributeError:
        pass
    # __delattr__调用
    del user.attr1